package dnl.toolbox.config;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import org.apache.commons.io.FileUtils;

/**
 * A simple utility to access resources in the Valire environment.
 * 
 * @author Daniel Orr
 * 
 */
public class Config {

	private static Config config = new Config();
	private File homeDir;
	private File tmpDir;
	private File dir4TempVars;
	private File attachmentsDir;
	private File orginalObjectsDir;
	private File projectionObjectsDir;
	private File reportsDir;

	private File reportFormatingDir;
	private File reportOutcomeDir;
	private File reportZipDir;
	private File reportUnZipDir;


	/*
	 * Resources are always in the absolute valire home and not like everything
	 * else that under dev are in target.
	 */
	private File resourcesDir;

	private Config() {
		init();
	}

	private void init() {

		String valireHomeDirName = System.getProperty("valireHome");
		if (valireHomeDirName != null) {
			assertHomeDir(valireHomeDirName);
		} else if (getEnvironmentVariable("VALIRE_HOME") != null) {
			valireHomeDirName = getEnvironmentVariable("VALIRE_HOME");
		} else {
			throw new IllegalStateException(
					"valire home should be set either using environment variable VALIRE_HOME or the system property valireHome.");
		}
		assertHomeDir(valireHomeDirName);
		resourcesDir = homeDir;

		System.out.println("Configuration is initialized using home=" + homeDir.getAbsolutePath());

		tmpDir = new File(getHomeDir(), "tmp");
		assertDirExists(tmpDir);
		
		attachmentsDir = new File(valireHomeDirName, "Attachments");
		assertDirExists(attachmentsDir);

		// directory for storing original objects data
		orginalObjectsDir = new File(getAttachmentsDir(), "Original");
		assertDirExists(orginalObjectsDir);

		// directory for storing projection objects (formatted objects)
		projectionObjectsDir = new File(getAttachmentsDir(), "Projection");
		assertDirExists(projectionObjectsDir);

		// reports
		reportsDir = new File(valireHomeDirName, "reports");
		assertDirExists(reportsDir);

		reportFormatingDir = new File(getReportsDir(), "formating");
		assertDirExists(reportFormatingDir);

		reportOutcomeDir = new File(getReportsDir(), "output");
		assertDirExists(reportOutcomeDir);

		reportZipDir = new File(getReportsDir(), "zip");
		assertDirExists(reportZipDir);

		reportUnZipDir = new File(getReportsDir(), "unZip");
		assertDirExists(reportUnZipDir);
	}

	private void assertHomeDir(String valireHomeDirName) {
		if (valireHomeDirName == null) {
			throw new IllegalStateException("VALIRE_HOME is not set.");
		}
		homeDir = new File(valireHomeDirName);
		if (!homeDir.exists()) {
			throw new IllegalStateException("Configured VALIRE_HOME ('" + homeDir.getAbsolutePath()
					+ "') does not exist.");
		}
		assertDirExists(homeDir);
	}

	private void assertDirExists(File f) {
		try {
			FileUtils.forceMkdir(f);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public File getHomeDir() {
		return homeDir;
	}

	public void setHomeDir(File homeDir) {
		this.homeDir = homeDir;
	}

	public File getDir4TempVars() {
		return dir4TempVars;
	}

	public File getTempDir() {
		return tmpDir;
	}

	public File getAttachmentsDir() {
		return attachmentsDir;
	}

	public InputStream getResource(String path) {
		URL url = getResourceAsUrl(path);
		if (url == null) {
			return null;
		}
		try {
			return url.openStream();
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}

	public URL getResourceAsUrl(String path) {
		File f = getFile(path);
		if (f.exists()) {
			try {
				return f.toURI().toURL();
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
		URL systemResource = ClassLoader.getSystemResource(path);
		if (systemResource != null) {
			try {
				FileUtils.copyURLToFile(systemResource, f);
			} catch (IOException e) {
				e.printStackTrace();
			}
			return systemResource;
		}
		return null;
	}

	public File getFile(String path) {
		File f = new File(resourcesDir.getAbsolutePath() + File.separator + path);
		return f;
	}

	/**
	 * Gets a resource from Valire's home directory.
	 * 
	 * @param path
	 *            a path relative to Valire's home directory.
	 * @return
	 */
	public static InputStream getValireResource(String path) {
		return config.getResource(path);
	}

	public static URL getValireResourceAsUrl(String path) {
		return config.getResourceAsUrl(path);
	}

	public static File getValireFile(String path) {
		return config.getFile(path);
	}

	public static File getValireHome() {
		return config.getHomeDir();
	}

	public static File getValireDir() {
		String sVDir = getEnvironmentVariable("VALIRE_DIR");
		return new File(sVDir);
	}

	public static File getValireTmpDir() {
		return new File(getValireHome(), "tmp");
	}

	private static String getEnvironmentVariable(String key) {
		Map<String, String> env = System.getenv();
		return env.get(key);
	}

	/**
	 * @return the orginalObjectsDir
	 */
	public File getOriginalObjectsDir() {
		return orginalObjectsDir;
	}

	/**
	 * @return the projectionObjectsDir
	 */
	public File getProjectionObjectsDir() {
		return projectionObjectsDir;
	}

	public File getReportsDir() {
		return reportsDir;
	}

	public void setReportsDir(File reportsDir) {
		this.reportsDir = reportsDir;
	}

	public File getReportFormatingDir() {
		return reportFormatingDir;
	}

	public void setReportFormatingDir(File reportFormatingDir) {
		this.reportFormatingDir = reportFormatingDir;
	}

	public File getReportOutcomeDir() {
		return reportOutcomeDir;
	}

	public void setReportOutcomeDir(File reportOutcomeDir) {
		this.reportOutcomeDir = reportOutcomeDir;
	}

	public File getReportZipDir() {
		return reportZipDir;
	}

	public void setReportZipDir(File reportZipDir) {
		this.reportZipDir = reportZipDir;
	}

	public File getReportUnZipDir() {
		return reportUnZipDir;
	}

	public void setReportUnZipDir(File reportUnZipDir) {
		this.reportUnZipDir = reportUnZipDir;
	}

}
